
#include <iostream>
#include "Intaddr.h"
#include "Log.h"
#include "Thread.h"
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

const char *ServeIp = "120.46.194.120";
const uint16_t ServePort = 8080;

// 使用多线程将收发信息进行分离...
void Send(int udp_id, zmh::Intaddr serve_addr)
{
    std::cout << "(Send->): 指令消息 --- #login登录,#quit退出" << std::endl;
    std::cout << "(Send->): 常规消息 --- 消息,将会转发给所有人" << std::endl;
    while (true)
    {
        // 发送数据
        std::cout << "(Send->):";
        std::string mes;
        std::getline(std::cin, mes);
        if (mes.size() == 0)
        {
            std::cout << "不能发送空白信息,请您重新输入！！！" << std::endl;
            continue;
        }

        if (sendto(udp_id, mes.c_str(), mes.size(), 0, (struct sockaddr *)&serve_addr.Addr(), sizeof(serve_addr.Addr())) == -1)
        {
            LOG(zmh::LogLevel::ERROR) << "send mistake:" << strerror(errno);
            exit(errno);
        }
        if (mes == "#quit")
            break;
    }
}

void Recv(int udp_id, zmh::Intaddr serve_addr)
{
    while (true)
    {
        // 接受数据
        char buffer[1024] = {0};
        struct sockaddr_in peer;
        socklen_t peerlen = sizeof(peer);
        int n = recvfrom(udp_id, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &peerlen);
        if (n == -1)
        {
            LOG(zmh::LogLevel::ERROR) << "recvfrom mistake:" << strerror(errno);
            exit(errno);
        }
        buffer[n] = 0;
        std::cerr << buffer << std::endl; // 收到的信息有两类: 1.谁发的？2.内容是啥？
    }
}

int main()
{
    zmh::Intaddr serve_addr(AF_INET, ServeIp, ServePort);
    int udp_id = socket(AF_INET, SOCK_DGRAM, 0);

    zmh::Thread S(Send, udp_id, serve_addr);
    zmh::Thread R(Recv, udp_id, serve_addr);

    // Send线程退出之后,Recv也退出 --- 主线程只阻塞等待Send线程
    S.join();
    R.cancel();
}

/*
    udp协议：
    1. socket获得套接字文件描述符
    2. 将自己的socket与其进行绑定 ---
       客户端不用显示bind,客户端第一次向服务器进行发消息的时候，就会操作系统就会自动bind和为其分配一个端口号
       原因1. 客户端会主动发消息
       原因2. 防止端口号冲突...
*/